/*
 ============================================================================
 Name        :	w.c
 Author      :	NAYED (nizar.ayed@fullcommedia.com)
 Version     :	0.1
 Copyright   :	Code delivered as is with no liability. No commercial use
 is allowed without written authorization from the Author. 
 Description :	Cf. "w.h"
 ============================================================================
 */

#include "w.h"
#include "w_parser.h"
#include "w_unit.h"

/* Initialization of the wVM */
void wVM_initialize(){
	_nil();
	_root();
}

/* Base */
void _nil(){
	universe = malloc (sizeof(object) * MAX_MEM);
	/* NIL, here, will reference the start of the universe. */
	/* It is his own clone. */
	nil = universe;
	nil->proto_id = nil;
	nil->owner_id = nil;
	nil->flags = NIL_OBJECT;
	nil->size = 0;
	/* NIL is "Nothing"! It has no name then :-) */
	nil->name = NULL;
	nil->payload = NULL;
}

void _root(){
	/* ROOT is the only clone of NIL (besides NIL itself, of course). */
	root = _clone(nil, "ROOT");
	/* Don't forget the flag (believe me, you will need this in the future). */
	if(root != nil) root->flags = ROOT_OBJECT;
}

object* _clone(object *prototype, char *name){
	object* clone = nil;
	if((object_number+1) == MAX_MEM){
		printf("Max number of objects reached. No new object is created.");
		return nil;
	}
	clone->proto_id = prototype;
	clone->owner_id = prototype;
	clone->flags = STANDARD_OBJECT;
	clone->size = 0;
	clone->name = name;
	/* In the future, perhaps, the following can be optimized to faster find	*/
	/* an object (using an object table for example).							*/
	object_number++;
	nil += sizeof(object);
	
	return clone;
}

object* clone_by_name(char *proto_name, char *name) {
	object *proto = _get_property(proto_name);
	return _clone(proto, name);
}

/* Object manipulation */
object* _get_property(char *obj_name){
	/* the Root object is the beginning of everything */
	object *obj = root;	
	/* Seek the object */
	while (obj != nil && (char *)obj->name != obj_name) {
		obj += sizeof(object);
	}
	/* if object not found, "nil" object is returned. */
	return obj;
}

void _own_property(object *owner, object *property) {
	property->owner_id = owner;
}

void own_property_by_name(object *owner, char *property_name) {
	object *property = _get_property(property_name);
	_own_property(owner, property);
}

void _set_payload(object *obj, char *payload){
	obj->payload = payload;
}

void set_payload_by_name(char *obj_name, char *payload){
	object *obj = _get_property(obj_name);
	_set_payload(obj, payload);
}

void _dump(object *obj){
	object* proto = obj->proto_id;
	object* owner = obj->owner_id;
	printf("obj_id:%p\t", obj);
	printf("pr:%s\t", proto->name);
	printf("ow:%s\t", owner->name);
	printf("fl:%i\t", obj->flags);
	printf("sz:%i\t", obj->size);
	printf("nm:%s\t", obj->name);
	printf("pl:%s\n", obj->payload);
}

void dump_by_name(char *obj_name){
	object *obj = _get_property(obj_name);
	_dump(obj);
}

void dump_all(){
	printf("Nb objects: %i\n", object_number);
	object *obj = universe;
	while (obj != nil) {
		_dump(obj);
		obj += sizeof(object);
	}
}

int main(int argc, char *argv[]) {
	/* Use of the console as input and output for now.
	 * the use of the file output will be implemented later.
	 */
	
	
	FILE *file;
	if(argc == 1) {
		puts("The file argument seems missing...");
		return EXIT_FAILURE;
	}
	file = fopen(argv[1], "r");
	if(file == NULL) {
		puts("Failed to open the file.");
		return EXIT_FAILURE;
	}
	
	verbose = true;
	
	test_array();
	
	/*
	 test_is_symbol('_', true);
	 test_is_symbol('$', true);
	 test_is_symbol('e', false);
	 test_is_letter('a', true);
	 test_is_letter('A', true);
	 test_is_letter('1', false);
	 test_is_alpha('_', true);
	 test_is_alpha('a', true);
	 test_is_alpha('1', false);
	 test_is_digit('0', true);
	 test_is_digit('$', false);
	 test_is_digit('d', false);
	 test_is_sign('+', true);
	 test_is_sign('-', true);
	 test_is_sign('d', false);
	 test_is_p_car('a', true);
	 test_is_p_car('~', true);
	 test_is_p_car('\t', false);
	 test_is_esc_car('a', true);
	 test_is_esc_car('n', true);
	 test_is_esc_car('z', false);
	 test_is_space(' ', true);
	 test_is_space('\n', true);
	 test_is_space('z', false);
	 
	 char t = '1';
	 printf("%d - %d = %d\n",
	 t, (t <= 'Z'), ((t >= 'A') && (t <= 'Z')) || ((t >= 'a') && (t <= 'z')));
	 */
	fclose(file);
	
	/*
	 wVM_initialize();
	 dump_all();
	 clone_by_name("ROOT", "obj1");
	 dump_all();
	 set_payload_by_name("obj1", "This is a standard object.");
	 dump_all();
	 clone_by_name("obj1", "obj2");
	 dump_all();
	 own_property_by_name(root,"obj2");
	 dump_all();
	 set_payload_by_name("obj2", "This is a principle.");
	 dump_all();
	 
	 //getchar();
	 */
	return EXIT_SUCCESS;
}
